/*
* ECARX Technology Limited is the owner of the copyright and the trade secret of this software.
* Without permission, no one has the right to obtain, disclose or use this software in any way.
*/

package ecarx.xsf.notificationcenter;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.RemoteException;
import android.os.UserManager;
import android.service.notification.StatusBarNotification;
import android.util.Log;

import androidx.annotation.NonNull;

import java.util.HashMap;

import ecarx.eas.notification.InitCallback;
import ecarx.eas.notification.StatusBarTyrantNotification;
import ecarx.eas.notification.interfaces.INotificationAPI;
import ecarx.eas.notification.interfaces.OnNotificationListener;
import ecarx.xsf.notificationcenter.common.Constants;
import ecarx.xsf.notificationcenter.interfaces.IMascotCardAPI;
import ecarx.xsf.notificationcenter.interfaces.INotificationListener;
import ecarx.xsf.notificationcenter.interfaces.ISceneCardAPI;
import ecarx.xsf.notificationcenter.interfaces.OnSceneCardListener;
import ecarx.xsf.notificationcenter.notification.ICardNotificationListener;
import ecarx.xsf.notificationcenter.notification.ILauncherControllerService;
import ecarx.xsf.notificationcenter.notification.INotificationBar;
import ecarx.xsf.notificationcenter.notification.INotificationService;
import ecarx.xsf.notificationcenter.scenecard.ISceneCardInfo;
import ecarx.xsf.notificationcenter.scenecard.ISceneCardListener;
import ecarx.xsf.notificationcenter.scenecard.ISceneCardListenerV2;
import ecarx.xsf.notificationcenter.scenecard.ISceneCardService;
import ecarx.xsf.notificationcenter.wrapper.MascotCardListenerWrapper;
import ecarx.xsf.notificationcenter.wrapper.NotificationListenerWrapper;
import ecarx.xsf.notificationcenter.wrapper.SceneCardListenerWrapper;

/**
 * FileName: LauncherControllerAPI.java <br>
 * Description : Launcher Controller API  <br>
 * Create Time: 2021/8/19 14:40 <br>
 * Update Time: 2021/8/19 14:40 <br>
 *
 * @since 1.0.0
 */
public class LauncherControllerApi extends BaseServiceAPI implements ISceneCardAPI, IMascotCardAPI, INotificationAPI {

    private static final String TAG = "LauncherControllerAPI";

    private static volatile LauncherControllerApi instance;

    private INotificationService iNotificationService;

    private ISceneCardService iSceneCardService;

    private ILauncherControllerService iLauncherControllerService;
    private final Context mContext;

    private final HashMap<OnNotificationListener, ecarx.xsf.notificationcenter.notification.INotificationListener.Stub> mNotificationListenerMap = new HashMap<>();

    private final HashMap<INotificationListener, ICardNotificationListener.Stub> mMascotListenerMap = new HashMap<>();

    private final HashMap<OnSceneCardListener, ISceneCardListenerV2.Stub> MSceneCardListenerMap = new HashMap<>();

    private BaseServiceConnection bscNotfication, bscMascot, bscSceneCard;


    public static LauncherControllerApi get(Context context) {
        if (instance == null) {
            synchronized (LauncherControllerApi.class) {
                if (instance == null) {
                    instance = new LauncherControllerApi(context);
                }
            }
        }
        return instance;
    }

    private LauncherControllerApi(Context context) {
        mContext = context;
    }

    @Override
    public void initAPI(InitCallback callback, String... apiNames) {

        if (apiNames == null || apiNames.length == 0) {
            throw new IllegalArgumentException("API Name is null");
        }

        UserManager mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
        for (String apiName : apiNames) {
            final BaseServiceConnection connection = new BaseServiceConnection(mContext, instance, apiName, callback);
            if (!checkAPI(apiName, connection)) {
                Log.e(TAG, "api name error");
                throw new IllegalArgumentException("API name is error");
            }
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !mUserManager.isUserUnlocked()) {
            IntentFilter intentFilter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
            intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
            mContext.registerReceiver(new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    connectService();
                }
            }, intentFilter);
        } else {
            connectService();
        }
    }

    /**
     * * 检查 API 名称是否一致.
     *
     * @param apiName    API 名称 {@link ecarx.xsf.notificationcenter.common.Constants.IAPINAME}
     * @param connection {@link BaseServiceConnection} 服务连接
     * @return 检查是否正常
     * @since 1.0.0
     */
    private boolean checkAPI(@NonNull String apiName, BaseServiceConnection connection) {
        switch (apiName) {
            case Constants.IAPINAME.NOTIFICATION_API:
                bscNotfication = connection;
                return true;
            case Constants.IAPINAME.SCENE_CARD_API:
                bscSceneCard = connection;
                return true;
            case Constants.IAPINAME.MASCOT_API:
                bscMascot = connection;
                return true;
        }
        return false;
    }


    /**
     * * 断开 API 连接，释放资源.
     * <p> 在页面退出后需释放资源 <br>
     *
     * @param apiName {@link ecarx.xsf.notificationcenter.common.Constants.IAPINAME} api 名称
     * @since 1.0.0
     */
    @Override
    public void release(String apiName) {
        switch (apiName) {
            case Constants.IAPINAME.NOTIFICATION_API:
                if (bscNotfication != null) {
                    bscNotfication.release();
                }
                break;
            case Constants.IAPINAME.SCENE_CARD_API:
                if (bscSceneCard != null) {
                    bscSceneCard.release();
                }
                break;
            case Constants.IAPINAME.MASCOT_API:
                if (bscMascot != null) {
                    bscMascot.release();
                }
                break;
        }
    }

    /**
     * * 添加通知中心消息监听.
     * <p> 通知中心数据通过监听回调的方式夸进程传输到客户端，客户端初始化 API 成功后必须添加消息监听器才可以接收到系统消息 <br>
     *
     * @param onNotificationListener 监听器 {@link OnNotificationListener}
     * @see StatusBarNotification
     * @see StatusBarTyrantNotification
     * @since 1.0.0
     */
    @Override
    public void addNotificationListener(final OnNotificationListener onNotificationListener) {
        if (iNotificationService == null) {
            logConnectError();
            return;
        }
        Log.i(TAG, "add notification listener");
        try {
            NotificationListenerWrapper notificationListener = new NotificationListenerWrapper(onNotificationListener);
            iNotificationService.addNotificationListener(notificationListener);
            mNotificationListenerMap.put(onNotificationListener, notificationListener);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    /**
     * * 移除消息监听器.
     * <p> 页面退出无需再监听系统通知消息或重新添加监听器时<br>
     *
     * @param onNotificationListener {@link OnNotificationListener} 监听器
     * @see #addNotificationListener(OnNotificationListener)
     * @since 1.0.0
     */
    @Override
    public void removeNotificationListener(OnNotificationListener onNotificationListener) {
        if (iNotificationService == null) {
            logConnectError();
            return;
        }
        Log.i(TAG, "remove notification listener");
        NotificationListenerWrapper listener = (NotificationListenerWrapper) mNotificationListenerMap.get(onNotificationListener);
        if (listener != null) {
            try {
                iNotificationService.removeNotificationListener(listener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * * 客户端取消通知.
     * <p> 客户端主动取消通知，并通知到系统 Launcher Controller <br>
     *
     * @param key 通知 key 值{@link StatusBarNotification#getKey()}
     * @see StatusBarNotification
     * @see StatusBarTyrantNotification
     * @since 1.0.0
     */
    @Override
    public void cancelNotification(String key) {
        if (iNotificationService == null) {
            logConnectError();
            return;
        }
        Log.i(TAG, "cancel notification " + key);
        try {
            iNotificationService.cancelNotification(key);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    /**
     * * 取消所有通知.
     * <p> 客户端主动取消所有通知，并通知到系统 Launcher Controller <br>
     *
     * @since 1.0.0
     */
    @Override
    public void cancelAllNotifications() {
        if (iNotificationService == null) {
            logConnectError();
            return;
        }
        Log.i(TAG, "cancel all notification");
        try {
            iNotificationService.cancelAllNotifications();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }


    /**
     * * 添加形象消息监听.
     * <p> 形象数据通过监听回调的方式夸进程传输到客户端，客户端初始化 API 成功后必须添加消息监听器才可以接收到系统消息 <br>
     *
     * @param listener 监听器 {@link INotificationListener}
     * @see #removeMascotCardListener(INotificationListener)
     * @since 1.0.0
     */
    @Override
    public void addMascotCardListener(INotificationListener listener) {
        if (iLauncherControllerService == null) {
            logConnectError();
            return;
        }

        try {
            Log.i(TAG, "add launcher controller api notification listener");
            MascotCardListenerWrapper wrapper = new MascotCardListenerWrapper(listener);
            iLauncherControllerService.addNotificationListener(wrapper);
            mMascotListenerMap.put(listener, wrapper);
        } catch (RemoteException e) {
            Log.e(TAG, "exception: " + e);
        }

    }

    /**
     * * 移除消息监听器.
     * <p> 页面退出无需再监听系统通知消息或重新添加监听器时<br>
     *
     * @param listener {@link INotificationListener} 监听器
     * @see #addMascotCardListener(INotificationListener)
     * @since 1.0.0
     */
    @Override
    public void removeMascotCardListener(INotificationListener listener) {
        if (iLauncherControllerService == null) {
            logConnectError();
            return;
        }
        Log.i(TAG, "remove mascot card listener");
        MascotCardListenerWrapper wrapper = (MascotCardListenerWrapper) mMascotListenerMap.get(listener);
        if (listener != null) {
            try {
                iLauncherControllerService.removeNotificationListener(wrapper);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 通知形象消息的处理状态.
     * <p> 当消息被处理或客户端主动让 Launcher Controller 系统在有消息的情况下下发下一条消息 <br>
     *
     * @param iNotificationBar {@link INotificationBar} 当前正常显示的消息
     * @param status           {@link ecarx.xsf.notificationcenter.common.Constants.ICardHandleStatus}
     * @since 1.0.0
     */
    @Override
    public void notifyCardHandleStatus(INotificationBar iNotificationBar, int status) {
        if (iLauncherControllerService == null) {
            logConnectError();
            return;
        }

        try {
            Log.i(TAG, "launcher controller api notify card handle status");
            iLauncherControllerService.notifyCardHandleStatus(iNotificationBar, status);
        } catch (RemoteException e) {
            Log.e(TAG, "exception: " + e);
        }

    }

    /**
     * * 添加智能卡片消息监听.
     * <p> 智能卡片数据通过监听回调的方式夸进程传输到客户端，客户端初始化 API 成功后必须添加消息监听器才可以接收到系统消息 <br>
     *
     * @param onSceneCardListener 监听器 {@link OnSceneCardListener}
     * @see ISceneCardInfo
     * @since 1.0.0
     */
    @Override
    public void addSceneCardListener(OnSceneCardListener onSceneCardListener) {
        if (iSceneCardService == null) {
            logConnectError();
            return;
        }

        try {
            SceneCardListenerWrapper wrapper = new SceneCardListenerWrapper(onSceneCardListener);
            iSceneCardService.addSceneCardListenerV2(wrapper);
            MSceneCardListenerMap.put(onSceneCardListener, wrapper);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    /**
     * * 移除消息监听器.
     * <p> 页面退出无需再监听系统智能卡片消息或重新添加监听器时<br>
     *
     * @param onSceneCardListener 监听器 {@link OnSceneCardListener}
     * @see #addSceneCardListener(OnSceneCardListener)
     * @since 1.0.0
     */
    @Override
    public void removeSceneCardListener(OnSceneCardListener onSceneCardListener) {
        if (iSceneCardService == null) {
            logConnectError();
            return;
        }
        Log.i(TAG, "remove scene card listener");
        ISceneCardListenerV2.Stub listener = MSceneCardListenerMap.get(onSceneCardListener);
        if (listener != null) {
            try {
                iSceneCardService.removeSceneCardListenerV2(listener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * * 消息状态发生改变，通知系统 Launcher Controller.
     * <p> 当消息被处理或客户端主动让 Launcher Controller 系统在有消息的情况下下发下一条智能卡片消息 <br>
     *
     * @param status 消息处理状态
     * @see ecarx.xsf.notificationcenter.common.Constants
     * @since 1.0.0
     */
    @Override
    public void notifySceneCardStatusChange(int status) {
        if (iSceneCardService == null) {
            logConnectError();
            return;
        }
        Log.i(TAG, "Scene Card API notify status change " + status);
        try {
            iSceneCardService.notifySceneCardStatusChange(status);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    private void logConnectError() {
        Log.e(TAG, "Please call initAPI method firstly and then call this after onInit(true)");
    }


    @Override
    void setNotificationService(INotificationService service) {
        iNotificationService = service;
    }

    @Override
    void setMascotCardService(ILauncherControllerService service) {
        iLauncherControllerService = service;
    }

    @Override
    void setSceneCardService(ISceneCardService service) {
        iSceneCardService = service;
    }

    @Override
    INotificationService getNotificationService() {
        return iNotificationService;
    }

    @Override
    ILauncherControllerService getMascotService() {
        return iLauncherControllerService;
    }

    @Override
    ISceneCardService getSceneCardService() {
        return iSceneCardService;
    }

    /**
     * 连接服务
     */
    private void connectService() {
        if (bscNotfication != null && !bscNotfication.isBindSuccess()) {
            bscNotfication.connectService();
        }

        if (bscMascot != null && !bscMascot.isBindSuccess()) {
            bscMascot.connectService();
        }

        if (bscSceneCard != null && !bscSceneCard.isBindSuccess()) {
            bscSceneCard.connectService();
        }
    }

}
